/*****************************************************************************
 *   Copyright 2005 Tim A Wang
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 ****************************************************************************/
package com.jb.java.tools;

//import com.sun.tools.javac.Main;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.PrintStream;


/**
 * Simple dynamic Java code implemenation. With a generator, it can compile,
 * save and execute generated code.
 */
public class DynamicJava implements Complier, Runner {
    static char fileSeparate = System.getProperty("file.separator").charAt(0);
    CodeGenerator codeGenerator;
    String errorStack = "";
    String rootDir;

    /**
    * Constructs a dyamnic java with a code generator and a root working directory.
    * @param codeGenerator code generator.
    * @param rootDir root working directory.
    */
    public DynamicJava(CodeGenerator codeGenerator, String rootDir) {
        this.codeGenerator = codeGenerator;
        this.rootDir = rootDir;
    }

    /**
    * Returns error stack as a string, compiling, or runtime.
    * @return error stack.
    */
    public String getErrorStack() {
        return errorStack;
    }

    /**
     * Compile generated code.
     * @param destDir to where compiled class is written.
     * @return true if successful.
     */
    public boolean compile(String destDir) {
        String[] source = { "-d", destDir, new String(getFileQName()) };
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        int status = -1;

        synchronized (System.err) {
            PrintStream err = System.err;
            System.setErr(new PrintStream(baos)); //hijack standard err
          //  status = Main.compile(source);
            System.setErr(err);
        }

        errorStack = baos.toString();

        return status == 0;
    }

    /**
     * Compile into current user directory.
     * @return true if successful.
     */
    public boolean compile() {
        String[] source = { new String(getFileQName()) };
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        int status = -1;

        synchronized (System.err) {
            PrintStream err = System.err;
            System.setErr(new PrintStream(baos)); //hijack standard err
      //      status = Main.compile(source);
            System.setErr(err);
        }

        errorStack = baos.toString();

        return status == 0;
    }

    /**
     * Executed generated code.
     */
    public void execute() {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            synchronized (System.err) {
                PrintStream err = System.err;
                PrintStream out = System.out;
                System.setErr(new PrintStream(baos)); //hijack standard err
                System.setOut(new PrintStream(baos)); //hijack standard out
                codeGenerator.getRunner().execute();
                System.setErr(err);
                System.setOut(out);
            }

            errorStack = baos.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Save generated code as a file.
     */
    public void save() {
        try {
            String dirName = codeGenerator.getPackageName().replace('.', fileSeparate);

            if (!(new File(rootDir + dirName)).exists()) {
                (new File(rootDir + dirName)).mkdirs();
            }

            FileWriter aWriter = new FileWriter(getFileQName(), false);
            aWriter.write(codeGenerator.getCode());
            aWriter.flush();
            aWriter.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String getFileQName() {
        return rootDir + codeGenerator.getClassQName().replace('.', fileSeparate) + ".java";
    }
}
